package com.example.myapplication2;

import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;

import android.os.*;
import android.text.method.ScrollingMovementMethod;
import android.view.ViewTreeObserver;
import android.widget.*;

import java.net.InetSocketAddress;
import java.nio.channels.SocketChannel;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.lang.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileInputStream;

import android.view.View;
import android.content.Intent;

class g_para {
    public static logClass l;
}

public class MainActivity extends AppCompatActivity {
    public LinkedList<String> log = new LinkedList<String>();
    boolean text = true;
    boolean hasStart = false;
    boolean logMode = true;
    int select = 1;
    boolean selectMode = false;
    Map<Integer, ArrayList<msgT>> msgCache = new HashMap<Integer, ArrayList<msgT>>();
    int cachePosMin = 0, cachePosMax = 0;
    boolean lock = false;
    int lockPos = 0;
    boolean stateChanged = false;
    int timeCo = 0, timeCo2 = 0;
    boolean keepBottom = false;
    LinkedList<String> chi = new LinkedList<String>();
    long seekBarTime = System.currentTimeMillis();
    boolean gotPong = false;

    void loadText() {
        try {
            String st = "config" + select + ".txt";
            File path = getBaseContext().getFilesDir();
            File file = new File(path, st);
            FileInputStream in = new FileInputStream(file);
            byte[] bytes = new byte[10000];
            in.read(bytes, 0, 10000);
            in.close();
            structWrapper re = new structWrapper(bytes);
            EditText ee;
            ee = (EditText) findViewById(R.id.ip_in);
            byte[] hh = re.readArr(re.readDWord());
            String jj = new String(hh, "UTF-8");
            ee.setText(jj);

            ee = (EditText) findViewById(R.id.port_in);
            ee.setText("" + re.readDWord());
            int ll = re.readDWord();
            ee = (EditText) findViewById(R.id.ssport_in);
            ee.setText("" + ll);
            ee = (EditText) findViewById(R.id.key_in);
            hh = re.readArr(re.readDWord());

            jj = new String(hh, "UTF-8");
            ee.setText(jj);

            ee = (EditText) findViewById(R.id.local_in);
            ee.setText("" + re.readDWord());

            ee = (EditText) findViewById(R.id.packlen_in);
            ee.setText("" + re.readDWord());

            ee = (EditText) findViewById(R.id.portNum_in);
            ee.setText("" + re.readDWord());

            ee = (EditText) findViewById(R.id.bufSize_in);
            ee.setText("" + re.readDWord());
            ee = (EditText) findViewById(R.id.maxLost_in);
            ee.setText("" + re.readDWord());
            ee = (EditText) findViewById(R.id.maxRecvPack_in);
            ee.setText("" + re.readDWord());
        } catch (Exception e) {

            TextView ed = (TextView) findViewById(R.id.log_view);
            String te = ed.getText().toString();
            ed.setText("未找到配置文件(" + e.toString() + ")\n\n" + te);
        }
    }

    void writeText() {
        EditText tt;
        tt = (EditText) findViewById(R.id.ip_in);
        String serverip = tt.getText().toString();

        tt = (EditText) findViewById(R.id.port_in);
        int serverport = Integer.parseInt(tt.getText().toString());

        tt = (EditText) findViewById(R.id.ssport_in);
        int ssPort = Integer.parseInt(tt.getText().toString());

        tt = (EditText) findViewById(R.id.key_in);
        String key = tt.getText().toString();

        tt = (EditText) findViewById(R.id.local_in);
        int localPort = Integer.parseInt(tt.getText().toString());

        tt = (EditText) findViewById(R.id.packlen_in);
        int packLen = Integer.parseInt(tt.getText().toString());
        tt = (EditText) findViewById(R.id.portNum_in);
        int portNum = Integer.parseInt(tt.getText().toString());

        tt = (EditText) findViewById(R.id.bufSize_in);
        int bufSize = Integer.parseInt(tt.getText().toString());

        tt = (EditText) findViewById(R.id.maxLost_in);
        int maxLost = Integer.parseInt(tt.getText().toString());

        tt = (EditText) findViewById(R.id.maxRecvPack_in);
        int maxRecv = Integer.parseInt(tt.getText().toString());

        try {
            String st = "config" + select + ".txt";
            File path = getBaseContext().getFilesDir();
            File file = new File(path, st);
            FileOutputStream stream = new FileOutputStream(file);
            structWrapper re = new structWrapper(10000);
            re.writeDWord(serverip.length());
            re.writeArr(serverip.getBytes());
            re.writeDWord(serverport);
            re.writeDWord(ssPort);
            re.writeDWord(key.length());
            re.writeArr(key.getBytes());
            re.writeDWord(localPort);
            re.writeDWord(packLen);
            re.writeDWord(portNum);
            re.writeDWord(bufSize);
            re.writeDWord(maxLost);
            re.writeDWord(maxRecv);
            stream.write(re.getWriteData());
            stream.close();
        } catch (Exception e) {
            TextView e1 = (TextView) findViewById(R.id.log_view);
            e1.setText(e.toString());
        }
    }

    void write(byte[] b) {
        try {
            String ss = "file.txt";
            File path = getBaseContext().getFilesDir();
            File f = new File(path, ss);
            FileOutputStream o = new FileOutputStream(f);
            o.write(b);
            o.close();
        } catch (Exception e) {
        }
    }

    byte[] get() {
        try {
            String ss = "file.txt";
            File path = getBaseContext().getFilesDir();
            File f = new File(path, ss);
            int l = (int) f.length();
            FileInputStream st = new FileInputStream(f);
            byte[] x = new byte[l];
            st.read(x);
            st.close();
            return x;
        } catch (Exception e) {
            return new byte[0];
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        this.getSupportActionBar().hide();
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        byte[] file = get();
        defaultChi.load(file);
        helpFunc.fileContent = file;
        SeekBar sk = (SeekBar) findViewById(R.id.seekBar);
        sk.setOnSeekBarChangeListener(new yourListener());
        ScrollView ss = (ScrollView) findViewById(R.id.log_scroll);
        ((Button) findViewById(R.id.select_btn)).setText("配置文件 " + select);
        ss.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
            @Override
            public void onScrollChanged() {
                ScrollView scroll = (ScrollView) findViewById(R.id.log_scroll);
                int xx = scroll.getChildAt(0).getBottom();
                int jj = scroll.getScrollY();
                if (!selectMode && !logMode) {
                    if (jj > 0.99 * xx)
                        keepBottom = true;
                }
                if (System.currentTimeMillis() - seekBarTime < 1000)
                    return;
                SeekBar sk = (SeekBar) findViewById(R.id.seekBar);

                if (xx > 0) {
                    float ff = (float) jj / xx;
                    sk.setProgress((int) (ff * sk.getMax()));
                }
            }
        });
        TextView ed = (TextView) findViewById(R.id.log_view);
        String info = "serverIp  | serverPort | ssPort\nkey | localPort\n" +
                "packLen | portNum\n" + "bufSize(KB) | maxLost | maxRecv\n" +
                "密码长度 = bufSize%10+2\n" +
                "maxLost为偶数发送damList\n" +
                "抽样刷新时间=maxRecv%5+1（可动态修改）\n" +
                "文件传输端口=localPort+1\n"+
                "maxRecv为0则删除file.txt\n" +
                "REFRESH按钮可更新bufSize | maxLost | maxRecv\n" +
                "log格式 : sock数，收到数，丢失数，时间差(10ms)，收到字节数，转化字节数，发送最大长度，对方收到最大长度，" +
                "对方发送最大长度，收到最大长度";

        ed.setText(info);
        loadText();
        final MainActivity chu = this;
        Switch mySwitch = (Switch) findViewById(R.id.start_btn);
        mySwitch.setText("抽样");
        mySwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if (!text)
                    stateChanged = true;
                logMode = !isChecked;
                if (!logMode) {
                    keepBottom = true;
                }
            }
        });

        Button button = (Button) findViewById(R.id.close_btn);
        button.setText("START");
        button.setOnClickListener(new MyOnClickListener_close(chu));
        button = (Button) findViewById(R.id.refresh_btn);
        button.setOnClickListener(new MyOnClickListener_refresh(chu));
        final ImageButton finalButton = (ImageButton) findViewById(R.id.text_btn);

        finalButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                text = !text;
                if (text)
                    finalButton.setImageResource(android.R.drawable.ic_media_pause);
                else
                    finalButton.setImageResource(android.R.drawable.ic_media_play);
            }
        });

        mySwitch = (Switch) findViewById(R.id.sel_btn);
        mySwitch.setText("全");
        mySwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                selectMode = isChecked;
                SeekBar sk = (SeekBar) findViewById(R.id.seekBar);
                if (selectMode) {
                    int ii = msgCache.size() - 1;
                    sk.setMax(20);
                    sk.setProgress(ii);
                    lock = false;
                    ((Button) findViewById(R.id.select_btn)).setText("查看" + ii);
                    lockPos = ii;
                } else {
                    while (cachePosMax - cachePosMin > 21) {
                        if (msgCache.containsKey(cachePosMin))
                            msgCache.remove(cachePosMin);
                        cachePosMin++;
                    }
                    ((Button) findViewById(R.id.select_btn)).setText("配置文件 " + select);
                    int tt = sk.getProgress();
                    sk.setMax(10000);
                    sk.setProgress(tt * 500);
                    if (!text)
                        stateChanged = true;
                }
            }
        });

        button = (Button) findViewById(R.id.select_btn);
        final Button finalButton2 = button;
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (selectMode) {
                    final SeekBar sk = (SeekBar) findViewById(R.id.seekBar);

                    if (!lock) {
                        if (!msgCache.containsKey(lockPos + cachePosMin)) {
                            finalButton2.setText("X");
                            final Handler handler = new Handler();
                            handler.postDelayed(new Runnable() {
                                @Override
                                public void run() {
                                    finalButton2.setText("查看" + lockPos);
                                }
                            }, 100);
                            return;
                        }
                    }

                    if (!lock) {
                        lock = true;
                        if (msgCache.get(lockPos + cachePosMin).size() > 130)
                            finalButton2.setText("在算");
                        final Handler handler = new Handler();
                        handler.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                ArrayList<msgT> t = msgCache.get(lockPos + cachePosMin);
                                finalButton2.setText(lockPos + "  (" + t.size() + ")  跳出");
                                StringBuilder builder = new StringBuilder();
                                int co = 0;
                                SimpleDateFormat ff = new SimpleDateFormat("mm′ ss.SSS″");
                                for (msgT one : t) {
                                    co++;
                                    builder.append("/******##########*******/\n\n");
                                    if (one.send) {
                                        builder.append(dam.b2chi(one.msg, "["
                                                + "<- " + ff.format(new Date(one.time)) + " (" + co + ") ]"));
                                        builder.append("\n");
                                    } else {
                                        builder.append(dam.b2chi(one.msg, "["
                                                + "-> " + ff.format(new Date(one.time)) + " (" + co + ") ]"));
                                        builder.append("\n");
                                    }
                                }
                                TextView e1 = (TextView) findViewById(R.id.log_view);
                                e1.setText(builder.toString());
                                e1.setTextSize(20);

                                final Handler handler = new Handler();
                                handler.postDelayed(new Runnable() {
                                    @Override
                                    public void run() {
                                        sk.setMax(10000);
                                        ScrollView scroll = (ScrollView) findViewById(R.id.log_scroll);
                                        int xx = scroll.getChildAt(0).getBottom();
                                        int jj = scroll.getScrollY();
                                        if (xx > 0) {
                                            float ff = (float) jj / xx;
                                            sk.setProgress((int) (ff * sk.getMax()));
                                        }
                                    }
                                }, 1);
                            }
                        }, 0);
                    } else {
                        lockPos--;
                        if (lockPos < 0) lockPos = 0;
                        lock = false;
                        finalButton2.setText("查看" + lockPos);
                        sk.setMax(20);
                        sk.setProgress(lockPos);
                    }
                    return;
                }
                select++;
                if (select == 5)
                    select = 1;
                String st = "配置文件 " + select;
                finalButton2.setText(st);
                chu.loadText();
            }
        });
    }

    void setLogChiT(ArrayList<msgT> l) {
        msgCache.put(cachePosMax, l);
        cachePosMax++;
        if (selectMode) {
            if (cachePosMax - cachePosMin > 50 && msgCache.containsKey(cachePosMax - 25)) {
                msgCache.remove(cachePosMax - 25);
            }
            return;
        }
        while (cachePosMax - cachePosMin > 21) {
            if (msgCache.containsKey(cachePosMin))
                msgCache.remove(cachePosMin);
            cachePosMin++;
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.O)
    void setLogChi(LinkedList<byte[]> sendL, LinkedList<byte[]> recvL) {
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("mm′ ss″");
        LocalDateTime now = LocalDateTime.now();
        for (byte[] a : sendL) {
            chi.add("/******##########*******/\n\n" + dam.b2chi(a, "[ <-- " + dtf.format(now) + "]"));
        }
        for (byte[] a : recvL) {
            chi.add("/******##########*******/\n\n" + dam.b2chi(a, "[ --> " + dtf.format(now) + "]"));
        }
        while (chi.size() > 70) chi.removeFirst();
        if (logMode || selectMode)
            return;
        if (!text && !stateChanged) return;
        if (!text && stateChanged)
            stateChanged = false;
        timeCo2++;
        if (timeCo2 < helpFunc.con_maxPackRecv % 5 + 1) return;
        timeCo2 = 0;
        StringBuilder builder = new StringBuilder();
        for (int lo = 0; lo < chi.size(); lo++) {
            builder.append(chi.get(lo));
            if (lo != chi.size() - 1)
                builder.append("\n");
        }

        TextView e1 = (TextView) findViewById(R.id.log_view);
        e1.setText(builder.toString());
        e1.setTextSize(20);
        if (!keepBottom) {
            if (System.currentTimeMillis() - seekBarTime < 1000)
                return;
            final Handler handler = new Handler();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    SeekBar sk = (SeekBar) findViewById(R.id.seekBar);
                    ScrollView scroll = (ScrollView) findViewById(R.id.log_scroll);
                    int xx = scroll.getChildAt(0).getBottom();
                    int jj = scroll.getScrollY();
                    if (xx > 0) {
                        float ff = (float) jj / xx;
                        sk.setProgress((int) (ff * sk.getMax()));
                    }
                }
            }, 1);
            return;
        }
        final ScrollView scroll = (ScrollView) findViewById(R.id.log_scroll);
        scroll.invalidate();
        scroll.requestLayout();
        final int xx = scroll.getChildAt(0).getBottom();
        scroll.scrollTo(0, (int) xx);
        if (System.currentTimeMillis() - seekBarTime < 1000)
            return;
        SeekBar sk = (SeekBar) findViewById(R.id.seekBar);
        sk.setProgress(sk.getMax());
        if (!text) {
            scroll.fling(0);
            final Handler handler = new Handler();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    final int xx = scroll.getChildAt(0).getBottom();
                    scroll.scrollTo(0, (int) xx);
                }
            }, 0);
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.O)
    void setLog2(String st) {
        if (st == "got pong")
        {
            gotPong = true;
            return;
        }

        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("ss");
        LocalDateTime now = LocalDateTime.now();
        ((TextView) findViewById(R.id.time_text)).setText(dtf.format(now));
        timeCo++;
        if (timeCo == 10) {
            timeCo = 0;
            dtf = DateTimeFormatter.ofPattern("mm′ ss″");
            now = LocalDateTime.now();
            String xx = "";
            if(gotPong)
            {
                gotPong=false;
                xx = " got pong";
            }
            log.add("######## " + dtf.format(now) + " ######## "+xx);
        }

        log.add(st);
        while (log.size() > 100) log.removeFirst();
        if (!logMode || selectMode) return;
        if (!text && !stateChanged) return;
        if (!text && stateChanged)
            stateChanged = false;

        StringBuilder builder = new StringBuilder();
        for (int lo = 0; lo < log.size(); lo++) {
            builder.append(log.get(lo));
            if (lo != log.size() - 1)
                builder.append("\n");
        }
        TextView e1 = (TextView) findViewById(R.id.log_view);
        e1.setText(builder.toString());
        e1.setTextSize(15);
        final ScrollView scroll = (ScrollView) findViewById(R.id.log_scroll);
        final int xx = scroll.getChildAt(0).getBottom();
        scroll.fling(0);
        final Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                scroll.scrollTo(0, (int) xx);
                if (System.currentTimeMillis() - seekBarTime < 1000)
                    return;
                SeekBar sk = (SeekBar) findViewById(R.id.seekBar);
                int jj = scroll.getScrollY();
                if (xx > 0) {
                    float ff = (float) jj / xx;
                    sk.setProgress((int) (ff * sk.getMax()));
                }
            }
        }, 1);
    }

    private class MyOnClickListener_close implements View.OnClickListener {
        private final MainActivity chu;

        public MyOnClickListener_close(MainActivity chu) {
            this.chu = chu;
        }

        @Override
        public void onClick(View view) {
            if (hasStart) {
                System.exit(0);
                return;
            }

            hasStart = true;
            ((Button) findViewById(R.id.close_btn)).setText("CLOSE");
            EditText tt;
            tt = (EditText) findViewById(R.id.ip_in);
            String serverip = tt.getText().toString();
            tt = (EditText) findViewById(R.id.port_in);
            int serverport = Integer.parseInt(tt.getText().toString());
            tt = (EditText) findViewById(R.id.ssport_in);
            int ssPort = Integer.parseInt(tt.getText().toString());

            tt = (EditText) findViewById(R.id.key_in);
            String key = tt.getText().toString();
            tt = (EditText) findViewById(R.id.local_in);
            int localPort = Integer.parseInt(tt.getText().toString());
            tt = (EditText) findViewById(R.id.packlen_in);
            int packLen = Integer.parseInt(tt.getText().toString());
            tt = (EditText) findViewById(R.id.portNum_in);
            int portNum = Integer.parseInt(tt.getText().toString());
            tt = (EditText) findViewById(R.id.bufSize_in);
            int bufSize = Integer.parseInt(tt.getText().toString());
            tt = (EditText) findViewById(R.id.maxLost_in);
            int maxLost = Integer.parseInt(tt.getText().toString());
            tt = (EditText) findViewById(R.id.maxRecvPack_in);
            int maxRecv = Integer.parseInt(tt.getText().toString());
            helpFunc.serverIp = serverip;
            helpFunc.server_port = serverport;
            helpFunc.con_ssPort = ssPort;
            if (maxLost % 2 == 0)
                helpFunc.hasDam = true;
            else
                helpFunc.hasDam = false;
            helpFunc.serverSenLen = helpFunc.cliSenLen = packLen;
            helpFunc.con_connBufSize = bufSize * 1024;
            helpFunc.calLen();
            helpFunc.con_serverKey = key.getBytes();
            helpFunc.con_localPort = localPort;
            helpFunc.maxNewSockPerSecond = maxLost;
            helpFunc.con_portsNum = portNum;
            helpFunc.con_maxPackRecv = maxRecv;
            if (maxRecv == 0) {
                try {
                    String ss = "file.txt";
                    File path = getBaseContext().getFilesDir();
                    File f = new File(path, ss);
                    f.delete();
                } catch (Exception e) {
                }
            }
            logClass ll = new logClass(chu);
            ll.setDaemon(true);
            g_para.l = ll;
            Intent it = new Intent(MainActivity.this, myServ.class);
            startService(it);
            chu.writeText();
        }
    }

    private class yourListener implements SeekBar.OnSeekBarChangeListener {
        public void onProgressChanged(SeekBar sk, int progress,
                                      boolean fromUser) {

            if (!fromUser) return;
            if (progress * 6 < sk.getMax() * 5 && !logMode && !selectMode && text)
                keepBottom = false;
            if (selectMode && !lock) {
                Button b = (Button) findViewById(R.id.select_btn);
                b.setText("查看" + progress);
                lockPos = progress;
                return;
            }
            final ScrollView scroll = (ScrollView) findViewById(R.id.log_scroll);
            final float xx = scroll.getChildAt(0).getBottom() * (float) progress / (float) sk.getMax();
            scroll.fling(0);
            final Handler handler = new Handler();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    scroll.scrollTo(0, (int) xx);
                }
            }, 1);
            seekBarTime = System.currentTimeMillis();
        }

        public void onStartTrackingTouch(SeekBar seekBar) {
        }

        public void onStopTrackingTouch(SeekBar seekBar) {
        }
    }

    private class MyOnClickListener_refresh implements View.OnClickListener {
        private final MainActivity chu;

        public MyOnClickListener_refresh(MainActivity chu) {
            this.chu = chu;
        }

        @Override
        public void onClick(View view) {
            EditText tt;
            tt = (EditText) findViewById(R.id.bufSize_in);
            int bufSize = Integer.parseInt(tt.getText().toString()) * 1024;
            tt = (EditText) findViewById(R.id.maxLost_in);
            int maxLost = Integer.parseInt(tt.getText().toString());
            tt = (EditText) findViewById(R.id.maxRecvPack_in);
            int maxRecv = Integer.parseInt(tt.getText().toString());
            helpFunc.con_maxPackRecv = maxRecv;
            refreshTHr aa = new refreshTHr(maxLost, bufSize);
            aa.setDaemon(true);
            aa.start();
            chu.writeText();
        }
    }
}

class refreshTHr extends Thread {
    int ports, bufSize;

    refreshTHr(int p, int b) {
        ports = p;
        bufSize = b;
    }

    public void run() {
        try {
            SocketChannel a = SocketChannel.open();
            InetSocketAddress add = new InetSocketAddress("127.0.0.1", helpFunc.newPortsControlPort);
            a.connect(add);
            myBuf w = new myBuf(4);
            w.writeWord(ports);
            helpFunc.tcpWrite(a, w.get());
            a.close();
            a = SocketChannel.open();
            add = new InetSocketAddress("127.0.0.1", helpFunc.bufControlPort);
            a.connect(add);
            w.clear();
            w.writeDWord(bufSize);
            helpFunc.tcpWrite(a, w.get());
            a.close();
        } catch (Exception e) {
        }
    }
}

class logClass extends Thread {
    MainActivity upper;

    void write(final byte[] b) {
        upper.runOnUiThread(new Runnable() {
            @RequiresApi(api = Build.VERSION_CODES.O)
            @Override
            public void run() {
                upper.write(b);
            }
        });
    }

    public logClass() {
    }

    public logClass(MainActivity a) {
        upper = a;
    }

    synchronized void setLog(final String st) {
        upper.runOnUiThread(new Runnable() {
            @RequiresApi(api = Build.VERSION_CODES.O)
            @Override
            public void run() {
                upper.setLog2(st);
            }
        });
    }

    void setLogChi(LinkedList<byte[]> a, LinkedList<byte[]> b) {
        final LinkedList<byte[]> aa = new LinkedList<byte[]>(a);
        final LinkedList<byte[]> bb = new LinkedList<byte[]>(b);
        upper.runOnUiThread(new Runnable() {
            @RequiresApi(api = Build.VERSION_CODES.O)
            @Override
            public void run() {
                upper.setLogChi(aa, bb);
            }
        });
    }

    void setLogChiT(ArrayList<msgT> a) {
        final ArrayList<msgT> aa = new ArrayList<msgT>(a);
        upper.runOnUiThread(new Runnable() {
            @RequiresApi(api = Build.VERSION_CODES.O)
            @Override
            public void run() {
                upper.setLogChiT(aa);
            }
        });
    }

    @RequiresApi(api = Build.VERSION_CODES.O)
    public void run() {
        try {
            touc.work(this);
        } catch (Exception e) {
            e.printStackTrace();
            setLog(e.toString());
        }
    }
}